package com.ecommerce.product.converter;

import com.alibaba.fastjson.JSON;
import com.ecommerce.dao.mybatis.mapper.ProductCategoryMapper;
import com.ecommerce.product.domain.Product;
import com.ecommerce.product.domain.ProductDocument;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Optional;

@Component
@AllArgsConstructor
public class ProductManualConverter {
    private final ProductConverterMapper mapper;
    private final ProductCategoryMapper categoryMapper;

    /**
     * Product 类型的对象转换为 ProductDocument 类型的对象。
     * 混合映射策略,MapStruct 基础映射 + 手动补充字段。
     * 混合映射更适合复杂业务场景，既能利用MapStruct的自动化优势，又能保持对特殊字段的精确控制。
     *
     * @param product
     * @return
     */
    public ProductDocument toFullDocument(Product product) {
        // 1. 基础字段通过MapStruct映射
        ProductDocument doc = mapper.toProductDocumentBase(product);

        // 2. 手动补充复杂字段
        /*
         * BigDecimal 转 String：
         * bigDecimal.toString()有科学计数法风险（如 1E+5 会变成 "1E+5"），
         * bigDecimal.toPlainString()可避免科学计数法，但尾部多余的零（如 100.00 → "100"），
         * 通用场景：优先选择 setScale + toPlainString，兼顾性能和精度控制，
         * 特殊需求：仅在需要动态格式化时使用 DecimalFormat，并注意线程安全问题
         * */

        //（1）设置价格，
        //方式1：使用 setScale + toPlainString，标准化字符串格式（财务级标准化存储，推荐大多数场景）
        doc.setPriceExact(product.getPrice().setScale(2, RoundingMode.HALF_UP).toPlainString());
        //方式2：带格式化的转换（需统一格式），使用DecimalFormat：如 "100.00" 或 "123.4567"
        doc.setPriceExact(new DecimalFormat("0.00##").format(product.getPrice()));

        //（2）处理规格转换
        if (StringUtils.isNotBlank(product.getSpecs())) {
            doc.setSpecs(parseSpecs(product.getSpecs()));
        }

        //（3）处理类目名称
        resolveCategoryNames(product, doc);

        return doc;
    }

    /**
     * 转换规格参数
     *
     * @param json
     * @return
     */
    private List<ProductDocument.Spec> parseSpecs(String json) {
        return JSON.parseArray(json, ProductDocument.Spec.class);
    }

    /**
     * 设置类目名称
     *
     * @param product
     * @param doc
     */
    private void resolveCategoryNames(Product product, ProductDocument doc) {
        Optional.ofNullable(product.getCategoryId())
                .map(categoryMapper::selectById)
                .ifPresent(c -> doc.setCategoryName(c.getName()));

        Optional.ofNullable(product.getSubCategoryId())
                .map(categoryMapper::selectById)
                .ifPresent(c -> doc.setSubCategoryName(c.getName()));
    }

    public ProductDocument toProductDocumentWithBaseInfo(Product product) {
        if (product == null) {
            return null;
        }

        return ProductDocument.builder()
                .id(product.getId())
                .name(product.getName())
                .code(product.getCode())
                //.price(product.getPrice())
                .stock(product.getStock())
                .productType(product.getProductType())
                .createTime(product.getCreateTime())
                .updateTime(product.getUpdateTime())
                .build();
    }
}
